{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "1cdd080f9ea3e0b",
   "metadata": {},
   "source": [
    "# ZepCloudChatMessageHistory\n",
    "> Recall, understand, and extract data from chat histories. Power personalized AI experiences.\n",
    "\n",
    ">[Zep](https://www.getzep.com) is a long-term memory service for AI Assistant apps.\n",
    "> With Zep, you can provide AI assistants with the ability to recall past conversations, no matter how distant,\n",
    "> while also reducing hallucinations, latency, and cost.\n",
    "\n",
    "> See [Zep Cloud Installation Guide](https://help.getzep.com/sdks) and more [Zep Cloud Langchain Examples](https://github.com/getzep/zep-python/tree/main/examples)\n",
    "\n",
    "## Example\n",
    "\n",
    "This notebook demonstrates how to use [Zep](https://www.getzep.com/) to persist chat history and use Zep Memory with your chain.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "82fb8484eed2ee9a",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-10T05:20:12.069045Z",
     "start_time": "2024-05-10T05:20:12.062518Z"
    }
   },
   "outputs": [],
   "source": [
    "from uuid import uuid4\n",
    "\n",
    "from langchain_community.chat_message_histories import ZepCloudChatMessageHistory\n",
    "from langchain_community.memory.zep_cloud_memory import ZepCloudMemory\n",
    "from langchain_core.messages import AIMessage, HumanMessage\n",
    "from langchain_core.output_parsers import StrOutputParser\n",
    "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n",
    "from langchain_core.runnables import (\n",
    "    RunnableParallel,\n",
    ")\n",
    "from langchain_core.runnables.history import RunnableWithMessageHistory\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "session_id = str(uuid4())  # This is a unique identifier for the session"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d79e0e737db426ac",
   "metadata": {},
   "source": [
    "Provide your OpenAI key"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "7430ea2341ecd227",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-10T05:20:17.983314Z",
     "start_time": "2024-05-10T05:20:13.805729Z"
    }
   },
   "outputs": [],
   "source": [
    "import getpass\n",
    "\n",
    "openai_key = getpass.getpass()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "81a87004bc92c3e2",
   "metadata": {},
   "source": [
    "Provide your Zep API key. See https://help.getzep.com/projects#api-keys\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "c21632a2c7223170",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-10T05:20:24.694643Z",
     "start_time": "2024-05-10T05:20:22.174681Z"
    }
   },
   "outputs": [],
   "source": [
    "zep_api_key = getpass.getpass()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "436de864fe0000",
   "metadata": {},
   "source": [
    "Preload some messages into the memory. The default message window is 4 messages. We want to push beyond this to demonstrate auto-summarization."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "e8fb07edd965ef1f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-10T05:20:38.657289Z",
     "start_time": "2024-05-10T05:20:26.981492Z"
    }
   },
   "outputs": [],
   "source": [
    "test_history = [\n",
    "    {\"role\": \"human\", \"content\": \"Who was Octavia Butler?\"},\n",
    "    {\n",
    "        \"role\": \"ai\",\n",
    "        \"content\": (\n",
    "            \"Octavia Estelle Butler (June 22, 1947 – February 24, 2006) was an American\"\n",
    "            \" science fiction author.\"\n",
    "        ),\n",
    "    },\n",
    "    {\"role\": \"human\", \"content\": \"Which books of hers were made into movies?\"},\n",
    "    {\n",
    "        \"role\": \"ai\",\n",
    "        \"content\": (\n",
    "            \"The most well-known adaptation of Octavia Butler's work is the FX series\"\n",
    "            \" Kindred, based on her novel of the same name.\"\n",
    "        ),\n",
    "    },\n",
    "    {\"role\": \"human\", \"content\": \"Who were her contemporaries?\"},\n",
    "    {\n",
    "        \"role\": \"ai\",\n",
    "        \"content\": (\n",
    "            \"Octavia Butler's contemporaries included Ursula K. Le Guin, Samuel R.\"\n",
    "            \" Delany, and Joanna Russ.\"\n",
    "        ),\n",
    "    },\n",
    "    {\"role\": \"human\", \"content\": \"What awards did she win?\"},\n",
    "    {\n",
    "        \"role\": \"ai\",\n",
    "        \"content\": (\n",
    "            \"Octavia Butler won the Hugo Award, the Nebula Award, and the MacArthur\"\n",
    "            \" Fellowship.\"\n",
    "        ),\n",
    "    },\n",
    "    {\n",
    "        \"role\": \"human\",\n",
    "        \"content\": \"Which other women sci-fi writers might I want to read?\",\n",
    "    },\n",
    "    {\n",
    "        \"role\": \"ai\",\n",
    "        \"content\": \"You might want to read Ursula K. Le Guin or Joanna Russ.\",\n",
    "    },\n",
    "    {\n",
    "        \"role\": \"human\",\n",
    "        \"content\": (\n",
    "            \"Write a short synopsis of Butler's book, Parable of the Sower. What is it\"\n",
    "            \" about?\"\n",
    "        ),\n",
    "    },\n",
    "    {\n",
    "        \"role\": \"ai\",\n",
    "        \"content\": (\n",
    "            \"Parable of the Sower is a science fiction novel by Octavia Butler,\"\n",
    "            \" published in 1993. It follows the story of Lauren Olamina, a young woman\"\n",
    "            \" living in a dystopian future where society has collapsed due to\"\n",
    "            \" environmental disasters, poverty, and violence.\"\n",
    "        ),\n",
    "        \"metadata\": {\"foo\": \"bar\"},\n",
    "    },\n",
    "]\n",
    "\n",
    "zep_memory = ZepCloudMemory(\n",
    "    session_id=session_id,\n",
    "    api_key=zep_api_key,\n",
    ")\n",
    "\n",
    "for msg in test_history:\n",
    "    zep_memory.chat_memory.add_message(\n",
    "        HumanMessage(content=msg[\"content\"])\n",
    "        if msg[\"role\"] == \"human\"\n",
    "        else AIMessage(content=msg[\"content\"])\n",
    "    )\n",
    "\n",
    "import time\n",
    "\n",
    "time.sleep(\n",
    "    10\n",
    ")  # Wait for the messages to be embedded and summarized, this happens asynchronously."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bfa6b19f0b501aea",
   "metadata": {},
   "source": [
    "**MessagesPlaceholder** - We’re using the variable name chat_history here. This will incorporate the chat history into the prompt.\n",
    "It’s important that this variable name aligns with the history_messages_key in the RunnableWithMessageHistory chain for seamless integration.\n",
    "\n",
    "**question** must match input_messages_key in `RunnableWithMessageHistory“ chain."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "2b12eccf9b4908eb",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-10T05:20:46.592163Z",
     "start_time": "2024-05-10T05:20:46.464326Z"
    }
   },
   "outputs": [],
   "source": [
    "template = \"\"\"Be helpful and answer the question below using the provided context:\n",
    "    \"\"\"\n",
    "answer_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", template),\n",
    "        MessagesPlaceholder(variable_name=\"chat_history\"),\n",
    "        (\"user\", \"{question}\"),\n",
    "    ]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7d6014d6fe7f2d22",
   "metadata": {},
   "source": [
    "We use RunnableWithMessageHistory to incorporate Zep’s Chat History into our chain. This class requires a session_id as a parameter when you activate the chain."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "83ea7322638f8ead",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-10T05:20:49.681754Z",
     "start_time": "2024-05-10T05:20:49.663404Z"
    }
   },
   "outputs": [],
   "source": [
    "inputs = RunnableParallel(\n",
    "    {\n",
    "        \"question\": lambda x: x[\"question\"],\n",
    "        \"chat_history\": lambda x: x[\"chat_history\"],\n",
    "    },\n",
    ")\n",
    "chain = RunnableWithMessageHistory(\n",
    "    inputs | answer_prompt | ChatOpenAI(openai_api_key=openai_key) | StrOutputParser(),\n",
    "    lambda s_id: ZepCloudChatMessageHistory(\n",
    "        session_id=s_id,  # This uniquely identifies the conversation, note that we are getting session id as chain configurable field\n",
    "        api_key=zep_api_key,\n",
    "        memory_type=\"perpetual\",\n",
    "    ),\n",
    "    input_messages_key=\"question\",\n",
    "    history_messages_key=\"chat_history\",\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "db8bdc1d0d7bb672",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-10T05:20:54.966758Z",
     "start_time": "2024-05-10T05:20:52.117440Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Parent run 622c6f75-3e4a-413d-ba20-558c1fea0d50 not found for run af12a4b1-e882-432d-834f-e9147465faf6. Treating as a root run.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'\"Parable of the Sower\" is relevant to the challenges facing contemporary society as it explores themes of environmental degradation, economic inequality, social unrest, and the search for hope and community in the face of chaos. The novel\\'s depiction of a dystopian future where society has collapsed due to environmental and economic crises serves as a cautionary tale about the potential consequences of our current societal and environmental challenges. By addressing issues such as climate change, social injustice, and the impact of technology on humanity, Octavia Butler\\'s work prompts readers to reflect on the pressing issues of our time and the importance of resilience, empathy, and collective action in building a better future.'"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.invoke(\n",
    "    {\n",
    "        \"question\": \"What is the book's relevance to the challenges facing contemporary society?\"\n",
    "    },\n",
    "    config={\"configurable\": {\"session_id\": session_id}},\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1d9c609652110db3",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
